/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkFlv/MkFlvDemuxer.h"
#include "MkFlv/MkFlvFileSource.h"
#include "MkFlv/MkFlvMuxer.h"
#include "MkEvent/MkTimer.h"
#include "MkUtil/MkFile.h"
#include <gtest/gtest.h>

void WriteBufferListToString(FILE* fp, const CMkBufferList& BufList)
{
    MkListBuffer::const_iterator it = BufList.GetBufferList().begin();
    for (; it != BufList.GetBufferList().end(); it++) {
        fwrite(it->GetBuffer(), 1, it->GetLength(), fp);
    }
}

TEST(MkFlvUt, FlvMuxerTest)
{
    MkString H264FileName = MkString(MkUtSourcePath) + "/test.264";
    MkString H265FileName = MkString(MkUtSourcePath) + "/test.265";
    MkString AacFileName = MkString(MkUtSourcePath) + "/test.aac";
    FILE *fp264 = fopen(H264FileName.c_str(), "rb");
    FILE *fp265 = fopen(H265FileName.c_str(), "rb");
    FILE *fpAac = fopen(AacFileName.c_str(), "rb");
    EXPECT_NE(nullptr, fp264);
    EXPECT_NE(nullptr, fp265);
    EXPECT_NE(nullptr, fpAac);
    CMkH264FileSource H264FileSource(fp264, nullptr);
    CMkH265FileSource H265FileSource(fp265, nullptr);
    CMkAacFileSource AacFileSource(fpAac, nullptr);
    Uint32 ErrorCode = H264FileSource.StartMediaSource(nullptr, nullptr);
    EXPECT_EQ(NoneError, ErrorCode);
    ErrorCode = H265FileSource.StartMediaSource(nullptr, nullptr);
    EXPECT_EQ(NoneError, ErrorCode);
    ErrorCode = AacFileSource.StartMediaSource(nullptr, nullptr);
    EXPECT_EQ(NoneError, ErrorCode);

    MkVector<MkEsPacket> VecPacket264;
    ErrorCode = H264FileSource.GetNextFrame(VecPacket264);
    EXPECT_EQ(NoneError, ErrorCode);

    MkVector<MkEsPacket> VecPacket265;
    ErrorCode = H265FileSource.GetNextFrame(VecPacket265);
    EXPECT_EQ(NoneError, ErrorCode);

    MkVector<MkEsPacket> VecPacketAac;
    ErrorCode = AacFileSource.GetNextFrame(VecPacketAac);
    EXPECT_EQ(NoneError, ErrorCode);

    MkString strModuleName;
    CMkFile::GetModuleFilePath(strModuleName);
    MkString H264AacFlvFileName = strModuleName + "/h264aac.flv";
    MkString H264FlvFileName = strModuleName + "/h264.flv";
    MkString H265FlvFileName = strModuleName + "/h265.flv";
    MkString AacFlvFileName = strModuleName + "/aac.flv";
    MkString H265AacFlvFileName = strModuleName + "/h265aac.flv";
    FILE *fpH264AacFlv = fopen(H264AacFlvFileName.c_str(), "wb");
    FILE *fpH264Flv = fopen(H264FlvFileName.c_str(), "wb");
    FILE *fpH265Flv = fopen(H265FlvFileName.c_str(), "wb");
    FILE *fpAacFlv = fopen(AacFlvFileName.c_str(), "wb");
    FILE *fpH265AacFlv = fopen(H265AacFlvFileName.c_str(), "wb");
    //packet 264 and aac to flv
    {
        Uint8 pBuf[Len1K] = { 0 };
        CMkBufferList BufferList;
        ErrorCode = CMkFlvMuxer::PacketHeader(H264FileSource.GetVideoParam(), AacFileSource.GetAudioParam(), 100, 10, pBuf, Len1K, BufferList);
        EXPECT_EQ(NoneError, ErrorCode);
        WriteBufferListToString(fpH264AacFlv, BufferList);
        BufferList.Clear();
        for (int i = 0; i < 100; i++) {
            Uint32 nUsed = 0;
            MkVector<MkEsPacket>::iterator it = VecPacket264.begin();
            for (; it != VecPacket264.end(); it++) {
                ErrorCode = CMkFlvMuxer::PacketEsPacket(H264FileSource.GetVideoParam(), AacFileSource.GetAudioParam(), *it, pBuf, Len1K, nUsed, BufferList);
                EXPECT_EQ(NoneError, ErrorCode);
                WriteBufferListToString(fpH264AacFlv, BufferList);
                BufferList.Clear();
            }

            it = VecPacketAac.begin();
            for (; it != VecPacketAac.end(); it++) {
                ErrorCode = CMkFlvMuxer::PacketEsPacket(H264FileSource.GetVideoParam(), AacFileSource.GetAudioParam(), *it, pBuf, Len1K, nUsed, BufferList);
                EXPECT_EQ(NoneError, ErrorCode);
                WriteBufferListToString(fpH264AacFlv, BufferList);
                BufferList.Clear();
            }
        }
    }

    //packet 265 and aac to flv
    {
        Uint8 pBuf[Len1K] = { 0 };
        CMkBufferList BufferList;
        ErrorCode = CMkFlvMuxer::PacketHeader(H265FileSource.GetVideoParam(), AacFileSource.GetAudioParam(), 100, 10, pBuf, Len1K, BufferList);
        EXPECT_EQ(NoneError, ErrorCode);
        WriteBufferListToString(fpH265AacFlv, BufferList);
        BufferList.Clear();
        for (int i = 0; i < 100; i++) {
            Uint32 nUsed = 0;
            MkVector<MkEsPacket>::iterator it = VecPacket265.begin();
            for (; it != VecPacket265.end(); it++) {
                ErrorCode = CMkFlvMuxer::PacketEsPacket(H265FileSource.GetVideoParam(), AacFileSource.GetAudioParam(), *it, pBuf, Len1K, nUsed, BufferList);
                EXPECT_EQ(NoneError, ErrorCode);
                WriteBufferListToString(fpH265AacFlv, BufferList);
                BufferList.Clear();
            }

            it = VecPacketAac.begin();
            for (; it != VecPacketAac.end(); it++) {
                ErrorCode = CMkFlvMuxer::PacketEsPacket(H265FileSource.GetVideoParam(), AacFileSource.GetAudioParam(), *it, pBuf, Len1K, nUsed, BufferList);
                EXPECT_EQ(NoneError, ErrorCode);
                WriteBufferListToString(fpH265AacFlv, BufferList);
                BufferList.Clear();
            }
        }
    }

    //packet 264 to flv
    {
        Uint8 pBuf[Len1K] = { 0 };
        CMkBufferList BufferList;
        ErrorCode = CMkFlvMuxer::PacketHeader(H264FileSource.GetVideoParam(), CMkAudioParam(), 100, 10, pBuf, Len1K, BufferList);
        EXPECT_EQ(NoneError, ErrorCode);
        WriteBufferListToString(fpH264Flv, BufferList);
        BufferList.Clear();
        for (int i = 0; i < 100; i++) {
            Uint32 nUsed = 0;
            MkVector<MkEsPacket>::iterator it = VecPacket264.begin();
            for (; it != VecPacket264.end(); it++) {
                ErrorCode = CMkFlvMuxer::PacketEsPacket(H264FileSource.GetVideoParam(), CMkAudioParam(), *it, pBuf, Len1K, nUsed, BufferList);
                EXPECT_EQ(NoneError, ErrorCode);
                WriteBufferListToString(fpH264Flv, BufferList);
                BufferList.Clear();
            }
        }
    }

    //packet 265 to flv
    {
        Uint8 pBuf[Len1K] = { 0 };
        CMkBufferList BufferList;
        ErrorCode = CMkFlvMuxer::PacketHeader(H265FileSource.GetVideoParam(), CMkAudioParam(), 100, 10, pBuf, Len1K, BufferList);
        EXPECT_EQ(NoneError, ErrorCode);
        WriteBufferListToString(fpH265Flv, BufferList);
        BufferList.Clear();
        for (int i = 0; i < 100; i++) {
            Uint32 nUsed = 0;
            MkVector<MkEsPacket>::iterator it = VecPacket265.begin();
            for (; it != VecPacket265.end(); it++) {
                ErrorCode = CMkFlvMuxer::PacketEsPacket(H265FileSource.GetVideoParam(), CMkAudioParam(), *it, pBuf, Len1K, nUsed, BufferList);
                EXPECT_EQ(NoneError, ErrorCode);
                WriteBufferListToString(fpH265Flv, BufferList);
                BufferList.Clear();
            }
        }
    }

    //packet aac to flv
    {
        Uint8 pBuf[Len1K] = { 0 };
        CMkBufferList BufferList;
        ErrorCode = CMkFlvMuxer::PacketHeader(CMkVideoParam(), AacFileSource.GetAudioParam(), 100, 10, pBuf, Len1K, BufferList);
        EXPECT_EQ(NoneError, ErrorCode);
        WriteBufferListToString(fpAacFlv, BufferList);
        BufferList.Clear();
        for (int i = 0; i < 100; i++) {
            Uint32 nUsed = 0;
            MkVector<MkEsPacket>::iterator it = VecPacketAac.begin();
            for (; it != VecPacketAac.end(); it++) {
                ErrorCode = CMkFlvMuxer::PacketEsPacket(CMkVideoParam(), AacFileSource.GetAudioParam(), *it, pBuf, Len1K, nUsed, BufferList);
                EXPECT_EQ(NoneError, ErrorCode);
                WriteBufferListToString(fpAacFlv, BufferList);
                BufferList.Clear();
            }
        }
    }
    fclose(fpH264AacFlv);
    fclose(fpH265AacFlv);
    fclose(fpH265Flv);
    fclose(fpH264Flv);
    fclose(fpAacFlv);

    //flv file source test
    FILE *fpH264AacFlvr = fopen(H264AacFlvFileName.c_str(), "rb");
    FILE *fpH264Flvr = fopen(H264FlvFileName.c_str(), "rb");
    FILE *fpH265Flvr = fopen(H265FlvFileName.c_str(), "rb");
    FILE *fpAacFlvr = fopen(AacFlvFileName.c_str(), "rb");
    FILE *fpH265AacFlvr = fopen(H265AacFlvFileName.c_str(), "rb");

    CMkFlvFileSource FlvH264AacFileSource(fpH264AacFlvr, nullptr);
    CMkFlvFileSource FlvH265AacFileSource(fpH265AacFlvr, nullptr);
    CMkFlvFileSource FlvH264FileSource(fpH264Flvr, nullptr);
    CMkFlvFileSource FlvH265FileSource(fpH265Flvr, nullptr);
    CMkFlvFileSource FlvAacFileSource(fpAacFlvr, nullptr);

    FlvH264AacFileSource.StartMediaSource(nullptr, nullptr);
    EXPECT_EQ(MkCodecH264, FlvH264AacFileSource.GetVideoParam().GetCodec());
    EXPECT_EQ(MkCodecAac, FlvH264AacFileSource.GetAudioParam().GetCodec());
    while (1) {
        MkVector<MkEsPacket> VecEsPacket;
        FlvH264AacFileSource.GetNextFrame(VecEsPacket);
        if (VecEsPacket.empty()
            || VecEsPacket.begin()->BufferList.Empty()) {
            break;
        }
    }

    FlvH265AacFileSource.StartMediaSource(nullptr, nullptr);
    EXPECT_EQ(MkCodecH265, FlvH265AacFileSource.GetVideoParam().GetCodec());
    EXPECT_EQ(MkCodecAac, FlvH265AacFileSource.GetAudioParam().GetCodec());
    while (1) {
        MkVector<MkEsPacket> VecEsPacket;
        FlvH265AacFileSource.GetNextFrame(VecEsPacket);
        if (VecEsPacket.empty()
            || VecEsPacket.begin()->BufferList.Empty()) {
            break;
        }
    }

    FlvH264FileSource.StartMediaSource(nullptr, nullptr);
    EXPECT_EQ(MkCodecH264, FlvH264FileSource.GetVideoParam().GetCodec());
    EXPECT_EQ(MkCodecUnknown, FlvH264FileSource.GetAudioParam().GetCodec());
    while (1) {
        MkVector<MkEsPacket> VecEsPacket;
        FlvH264FileSource.GetNextFrame(VecEsPacket);
        if (VecEsPacket.empty()
            || VecEsPacket.begin()->BufferList.Empty()) {
            break;
        }
    }

    FlvH265FileSource.StartMediaSource(nullptr, nullptr);
    EXPECT_EQ(MkCodecH265, FlvH265FileSource.GetVideoParam().GetCodec());
    EXPECT_EQ(MkCodecUnknown, FlvH265FileSource.GetAudioParam().GetCodec());
    while (1) {
        MkVector<MkEsPacket> VecEsPacket;
        FlvH265FileSource.GetNextFrame(VecEsPacket);
        if (VecEsPacket.empty()
            || VecEsPacket.begin()->BufferList.Empty()) {
            break;
        }
    }

    FlvAacFileSource.StartMediaSource(nullptr, nullptr);
    EXPECT_EQ(MkCodecUnknown, FlvAacFileSource.GetVideoParam().GetCodec());
    EXPECT_EQ(MkCodecAac, FlvAacFileSource.GetAudioParam().GetCodec());
    while (1) {
        MkVector<MkEsPacket> VecEsPacket;
        FlvAacFileSource.GetNextFrame(VecEsPacket);
        if (VecEsPacket.empty()
            || VecEsPacket.begin()->BufferList.Empty()) {
            break;
        }
    }

    FlvH264AacFileSource.StopMediaSource();
    FlvH265AacFileSource.StopMediaSource();
    FlvH264FileSource.StopMediaSource();
    FlvH265FileSource.StopMediaSource();
    FlvAacFileSource.StopMediaSource();
    CMkFile::DeleteLocalFile(H264AacFlvFileName);
    CMkFile::DeleteLocalFile(H265AacFlvFileName);
    CMkFile::DeleteLocalFile(H264FlvFileName);
    CMkFile::DeleteLocalFile(H265FlvFileName);
    CMkFile::DeleteLocalFile(AacFlvFileName);
}